﻿using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI.WebControls.Adapters;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;

namespace MyWebPagesStarterKit.Controls
{
    /// <summary>
    /// MenuHelper
    /// Helper to make it easier to create a level of ul li elements from a SiteMap. 
    /// Automatically creates expanded and hidden levels.
    /// Only Css needed is .collapsed {display:none;}
    /// Population of menues are separate to create customizations easier.
    /// </summary>
    public class CssMenu : WebControl
    {
        private string _CssClassSelected = "selected"; //default css
        private string _MenuClass;
        private bool _ShowExpand = false;
        private SiteMapNode levelRoot;
        private bool _ShowTopLevelsOnly = false;
        private bool _ShowCompleteMenu = false;
        private bool _UseCustomTitle = false;

        protected override void OnLoad(EventArgs e)
        {
            if(this._ShowCompleteMenu)
                Page.ClientScript.RegisterClientScriptInclude("MenuControl", "/scripts/menu.js");
        }

        /// <summary>
        /// Render menu
        /// </summary>
        /// <param name="writer">Current HtmlTextWriter</param>
        protected override void Render(HtmlTextWriter writer)
        {
            if (SiteMap.CurrentNode != null)
            {
                if (_ShowTopLevelsOnly) //Only display toplevel items
                {
                    PopulateTopMenu(SiteMap.RootNode, writer);
                }
                else if (_ShowCompleteMenu)
                {
                    writer.WriteBeginTag("ul");
                    writer.WriteAttribute("class", MenuClass);
                    writer.WriteAttribute("id", this.ID);
                    writer.Write(HtmlTextWriter.TagRightChar);
                    writer.Indent++;

                    PopulateCompleteMenu(SiteMap.RootNode, writer);
                    writer.Indent--;
                    writer.WriteLine();
                    writer.WriteEndTag("ul");
                }
                else
                {
                    levelRoot = GetLevelRoot(SiteMap.CurrentNode);

                    if (levelRoot.HasChildNodes) //W3C doesn't validate if a ul with no list elements inside.
                    {
                        if (levelRoot.ChildNodes[0]["hidden"] != "false") //Check if first node is hidden. Causes validation to fail if no items in ul.
                        {
                            writer.Indent++;
                            writer.WriteLine();
                            writer.WriteBeginTag("ul");
                            writer.WriteAttribute("class", MenuClass);
                            writer.WriteAttribute("id", MenuClass);
                            writer.Write(HtmlTextWriter.TagRightChar);

                            PopulateMenu(levelRoot, writer);

                            writer.Indent--;
                            writer.WriteLine();

                            writer.WriteEndTag("ul");
                            writer.WriteLine();
                        }
                    }
                }
            }
        }


        private string GetLinkedUrl(SiteMapNode node)
        {
            if (string.IsNullOrEmpty(node["linkedto"]))
                return node.Url;
            else
                return new WebPage(node["linkedto"]).VirtualPath.Replace("~/", "");
        }


        private string GetLinkedTitle(SiteMapNode node)
        {
            if (string.IsNullOrEmpty(node["linkedto"]))
                return node.Title;
            else
                return new WebPage(node["linkedto"]).Title;
        }

        /// <summary>
        /// Displays only toplevel items
        /// </summary>
        /// <param name="rootNode">This Sitemaps RootNode</param>
        /// <param name="writer">HtmlTextWriter (html output)</param>
        private void PopulateTopMenu(SiteMapNode rootNode, HtmlTextWriter writer)
        {
            writer.WriteBeginTag("ul");
            writer.WriteAttribute("class", MenuClass);
            writer.WriteAttribute("id", MenuClass);
            writer.Write(HtmlTextWriter.TagRightChar);

            writer.Indent++;
            writer.WriteLine();

            foreach (SiteMapNode node in rootNode.ChildNodes)
            {
                if (!Convert.ToBoolean(node["hidden"]))
                {
                    writer.Indent++;
                    writer.WriteBeginTag("li");
                    writer.Write(HtmlTextWriter.TagRightChar);
                  
                    //a
                    writer.WriteBeginTag("a");
                    writer.WriteAttribute("href", string.Format("{0}", GetLinkedUrl(node)));
                   
                    bool isPath;
                    IsInPath(node.ChildNodes, out isPath); //If node is in the current node's path.

                    if (node.Equals(SiteMap.CurrentNode) || isPath)
                        writer.WriteAttribute("class", _CssClassSelected); //Clicked item(currentNode)

                    writer.Write(HtmlTextWriter.TagRightChar);
                    //writer.Write("<span>"); //Removed Dj Ankur
                    if (_UseCustomTitle)
                        writer.Write(node.Title);
                    else
                        writer.Write(GetLinkedTitle(node));
                    //writer.Write("</span>"); //Removed Dj Ankur
                    writer.WriteEndTag("a");
                    writer.WriteEndTag("li");
                    writer.Indent--;
                    writer.WriteLine();

                }
            }
            writer.Indent--;
            writer.WriteLine();
            writer.WriteEndTag("ul");
        }



        /// <summary>
        /// Populates a ul li treemenu (Leveled ul li menu)
        /// </summary>
        /// <param name="parentNode">SiteMapNode parentNode</param>
        /// <param name="writer">HtmlTextWriter writer</param>
        private void PopulateMenu(SiteMapNode parentNode, HtmlTextWriter writer)
        {
            foreach (SiteMapNode node in parentNode.ChildNodes)
            {
                if (!Convert.ToBoolean(node["hidden"]))
                {
                    //li
                    writer.WriteBeginTag("li");
                    writer.Write(HtmlTextWriter.TagRightChar);

                    writer.Indent++;
                    writer.WriteLine();
                   
                    //a
                    writer.WriteBeginTag("a");
                    writer.WriteAttribute("href", string.Format("{0}", GetLinkedUrl(node)));

                    if (node.Equals(SiteMap.CurrentNode))
                        writer.WriteAttribute("class", _CssClassSelected); //Clicked item(currentNode)
                    
                    writer.Write(HtmlTextWriter.TagRightChar);
                    writer.Write("<span>");

                    if (_ShowExpand && node.HasChildNodes)
                        writer.Write(" +");

                    if (_UseCustomTitle)
                        writer.Write(node.Title);
                    else
                        writer.Write(GetLinkedTitle(node));

                    writer.Write("</span>");
                    writer.WriteEndTag("a");

                   
                    if (node.HasChildNodes) //Write out ul element if node has childNodes
                    {
                        writer.WriteBeginTag("ul");

                        bool isPath;
                        IsInPath(node.ChildNodes, out isPath); //If node is in the current node's path.

                        if (SiteMap.CurrentNode.Equals(node) || isPath)
                            writer.WriteAttribute("class", "expanded"); //Show element
                        else
                            writer.WriteAttribute("class", "collapsed"); //Hide element

                        writer.Write(HtmlTextWriter.TagRightChar);

                        PopulateMenu(node, writer); //Get all childnodes from this node
                        writer.WriteEndTag("ul");
                    }
       
                    writer.WriteLine();
                    writer.WriteEndTag("li");
                }
            }
        }


        /// <summary>
        /// Populates a ul li treemenu (Leveled ul li menu)
        /// </summary>
        /// <param name="parentNode">SiteMapNode parentNode</param>
        /// <param name="writer">HtmlTextWriter writer</param>
        private void PopulateCompleteMenu(SiteMapNode parentNode, HtmlTextWriter writer)
        {
            foreach (SiteMapNode node in parentNode.ChildNodes)
            {
                if (!Convert.ToBoolean(node["hidden"]))
                {
                    //li
                    writer.WriteBeginTag("li");
                    writer.Write(HtmlTextWriter.TagRightChar);

                    //a
                    writer.WriteBeginTag("a");
                    writer.WriteAttribute("href", string.Format("{0}", GetLinkedUrl(node)));

                    if (node.Equals(SiteMap.CurrentNode))
                        writer.WriteAttribute("class", _CssClassSelected); //Clicked item(currentNode)

                    writer.Write(HtmlTextWriter.TagRightChar);
                    writer.Write("<span>");
                    if (_UseCustomTitle)
                        writer.Write(node.Title);
                    else
                        writer.Write(GetLinkedTitle(node));
                    writer.Write("</span>");
                    writer.WriteEndTag("a");


                    if (node.HasChildNodes) //Write out ul element if node has childNodes
                    {
                        writer.WriteBeginTag("ul");

                        bool isPath;
                        IsInPath(node.ChildNodes, out isPath); //If node is in the current node's path.

                        if (SiteMap.CurrentNode.Equals(node) || isPath)
                            writer.WriteAttribute("class", "expanded"); //Show element
                        else
                            writer.WriteAttribute("class", "collapsed"); //Hide element

                        writer.Write(HtmlTextWriter.TagRightChar);

                        PopulateMenu(node, writer); //Get all childnodes from this node
                        writer.WriteEndTag("ul");
                    }

                    writer.WriteEndTag("li");
                }
            }
        }

        /// <summary>
        /// Searches from current level after the current node, if the SiteMapNode is found it returns true.
        /// </summary>
        /// <param name="nodes">SiteMapNodeCollection parentNodes</param>
        /// <param name="isInPath">out bool if found</param>
        private void IsInPath(SiteMapNodeCollection nodes, out bool isInPath)
        {
            isInPath = false;

            foreach (SiteMapNode child in nodes)
            {
                if (child.Equals(SiteMap.CurrentNode))
                {
                    isInPath = true;
                    break;
                }
                else
                {
                    IsInPath(child.ChildNodes, out isInPath);
                }

                if (isInPath)
                    break;
            }
        }


        /// <summary>
        /// Gets the first node below root in current level
        /// </summary>
        /// <param name="node">Get the node at position 1, first node below rootnode.</param>
        /// <returns>The top level node below root</returns>
        private System.Web.SiteMapNode GetLevelRoot(System.Web.SiteMapNode node)
        {
            if (node != null)
            {
                if (node.ParentNode != null)
                {
                    while (!node.ParentNode.Equals(System.Web.SiteMap.RootNode))
                        node = node.ParentNode;
                }
            }
            return node;
        }


        /// <summary>
        /// Css classname of ul menu.
        /// </summary>
        public string MenuClass
        {
            get {
                if (string.IsNullOrEmpty(_MenuClass))
                    return this.ClientID;
                else
                    return _MenuClass;
            }
                
            set { _MenuClass = value; }
        }


        /// <summary>
        /// Css classname of a selected listitem.
        /// </summary>
        public string CssClassSelected
        {
            get { return _CssClassSelected; }
            set { _CssClassSelected = value; }
        }


        /// <summary>
        /// Add a "+" sign in links that has sublevels.
        /// </summary>
        public bool ShowExpand
        {
            get { return _ShowExpand; }

            set { _ShowExpand = value; }
        }


        /// <summary>
        /// Display only toplevel items.
        /// For eg a topmenu.
        /// </summary>
        public bool ShowTopLevelsOnly
        {
            get { return _ShowTopLevelsOnly; }
            set { _ShowTopLevelsOnly = value; }
        }

        /// <summary>
        /// Display all items.
        /// </summary>
        public bool ShowCompleteMenu
        {
            get { return _ShowCompleteMenu; }
            set { _ShowCompleteMenu = value; }
        }


        /// <summary>
        /// Displays the title from the node you creating. Working toghether with the LinkedTo
        /// It uses the nodes url, but the webpage NavigationName from the LinkedTo webpage
        /// </summary>
        public bool UseCustomTitle
        {
            get { return _UseCustomTitle; }
            set { _UseCustomTitle = value; }
        }
    }
}
